#include <nss.h>
#include <pwd.h>
#include <shadow.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include<signal.h>
#define MIN_UID_NUMBER   500
#define MIN_GID_NUMBER   500
#define MACH_NAME "/etc/hostname"

/*
 * The passwd structure in <pwd.h>
struct passwd
{
	char *pw_name;               // Username.
	char *pw_passwd;              //Password.
	__uid_t pw_uid;              // User ID.
	__gid_t pw_gid;              // Group ID.
	char *pw_gecos;              // Real name.
	char *pw_dir;                // Home directory.
	char *pw_shell;              // Shell program.
};

shadow passwd structure in <shadow.h>

struct spwd
{
	char *sp_namp;          Login name
	char *sp_pwdp;          Encrypted password
	long sp_lstchg;         Date of last change
	long sp_min;            Min #days between changes
	long sp_max;            Max #days between changes
	long sp_warn;           #days before pwd expires to warn user to change it
	long sp_inact;          #days after pwd expires until account is disabled
	long sp_expire;         #days since 1970-01-01 until account is disabled
	unsigned long sp_flag;  Reserved
};

*/

struct passwdbuff
{
        char pw_name[100];              //  Username.
		char pw_passwd[100];             // Password.
		__uid_t pw_uid;              // User ID.
		__gid_t pw_gid;             //  Group ID.
		char pw_gecos[100];              // Real name.
		char pw_dir[100];                // Home directory.
		char pw_shell[100];             //  Shell program.

};
struct Machnamestruct
{
    int  Enable;
    char Machname[100];
};
//返回本机名
struct Machnamestruct
readMachname()
{
    struct Machnamestruct Mach;
    memset(&Mach,0x00,sizeof(struct Machnamestruct));
    FILE *fd;
	char buff[100];
	if ((fd = fopen(MACH_NAME, "r")) == NULL )
	{
        Mach.Enable=0;
	}
	//读取机器名字到buff
    if (fgets (buff, BUFSIZ, fd) == NULL)
    {
		fclose(fd);
        Mach.Enable=0;
	}
	Mach.Enable=1;
	strcpy(Mach.Machname,buff);
	return Mach;

}
//请求数据格式
 struct RequInfo
      {
        char RequInfo[100];
        char Param[100];
        char Machname[100];
      };

//buffer 管理
static char *
get_static(char **buffer, size_t *buflen, int len)
{
	char *result;

	/* Error check.  We return false if things aren't set up right, or
         * there isn't enough buffer space left. */

	if ((buffer == NULL) || (buflen == NULL) || (*buflen < len)) {
		return NULL;
	}

	/* Return an index into the static buffer */

	result = *buffer;
	*buffer += len;
	*buflen -= len;

	return result;
}

enum nss_status
_nss_ato_getpwnam_r( const char *name,struct passwd *p,char *buffer,size_t buflen,int *errnop)
{
    signal(SIGPIPE,SIG_IGN);
    struct RequInfo Req;//请求参数的结构体
    memset(&Req,0x00,sizeof(struct RequInfo));
    strcpy(Req.RequInfo,"USER");
    strcpy(Req.Param,name);
    struct Machnamestruct Resu=readMachname();
    strcpy(Req.Machname,Resu.Machname);
    //socket 通信
    struct sockaddr_in stSockAddr;
    int Res;
    //套接字描述
    int SocketFD = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (-1 == SocketFD) return NSS_STATUS_TRYAGAIN;
    //清空
    memset(&stSockAddr, 0, sizeof(struct sockaddr_in));

    stSockAddr.sin_family = AF_INET;
    stSockAddr.sin_port = htons(5555);//服务器端口号
    Res = inet_pton(AF_INET, "211.87.230.12", &stSockAddr.sin_addr);//服务器IP地址（转换为网络字节）

    if (0 >= Res)
        return NSS_STATUS_TRYAGAIN;
    if (-1 == connect(SocketFD, (const struct sockaddr *)&stSockAddr, sizeof(struct sockaddr_in)))
    {
        return NSS_STATUS_TRYAGAIN;
    }
    //发送请求的参数到服务端
    send(SocketFD,&Req,sizeof(Req),0);
    memset(buffer,0x00,sizeof(buffer));
    struct passwdbuff pbuff;
    if(recv(SocketFD,&pbuff,sizeof(pbuff),0)<0)
        return NSS_STATUS_TRYAGAIN;
    //拷贝数据
    p->pw_name = get_static(&buffer, &buflen, strlen(pbuff.pw_name) + 1);
    strcpy(p->pw_name,pbuff.pw_name);
    p->pw_passwd = get_static(&buffer, &buflen, strlen("x") + 1);
    strcpy(p->pw_passwd,"x");
    p->pw_uid=pbuff.pw_uid;
    p->pw_gid=pbuff.pw_gid;
    p->pw_gecos = get_static(&buffer, &buflen, strlen(pbuff.pw_gecos) + 1 );
    p->pw_dir = get_static(&buffer, &buflen, strlen(pbuff.pw_dir) + 1 );
    strcpy(p->pw_dir,pbuff.pw_dir);
    p->pw_shell = get_static(&buffer, &buflen, strlen(pbuff.pw_shell) + 1 );
    strcpy(p->pw_shell,pbuff.pw_shell);
    send(SocketFD,&pbuff.pw_name,sizeof(pbuff.pw_name),0);
    close(SocketFD);
    return NSS_STATUS_SUCCESS;

}

enum nss_status
_nss_ato_getspnam_r( const char *name,
                     struct spwd *s,
                     char *buffer,
                     size_t buflen,
                     int *errnop)
{

        /* If out of memory */
/*        if ((s->sp_namp = get_static(&buffer, &buflen, strlen(name) + 1)) == NULL) {
                return NSS_STATUS_TRYAGAIN;
        }*/

        strcpy(s->sp_namp, name);
/*
        if ((s->sp_pwdp = get_static(&buffer, &buflen, strlen("!") + 1)) == NULL) {
                return NSS_STATUS_TRYAGAIN;
        }*/

        strcpy(s->sp_pwdp, "!");

        s->sp_lstchg = 13571;
        s->sp_min    = 0;
        s->sp_max    = 99999;
        s->sp_warn   = 7;

        return NSS_STATUS_SUCCESS;
}
